Переменные и их области видимости
Переменные
Переменные
Переменная (Variable) – это именованное место в памяти, где хранится значение определённого типа. на позволяет программе запоминать, использовать и изменять данные в процессе выполнения.
Базовый шаблон объявления переменной с явным указанием типа:
<тип> <имя>;
Примеры реализации:
int age;
string username;
bool isActive;
double price;
Определение:
- тип данных: определяет, какие данные может хранить переменная (int, string, bool и т.д.);
- имя: уникальный идентификатор, по которому к переменной можно обратиться;
- значение: то, что хранится в переменной (например, 25).
Объявление и инициализация переменной:
int age; // Объявление
age = 25; // Инициализация
string message = "Добро пожаловать"; // Одновременное объявление и инициализация
Здесь:
- int, string - тип;
- age, message - имя;
- 25, “Добро пожаловать” - значение.
Синтаксис прост:
тип имя = значение; // инициализация
или
тип имя; // объявление
имя = значение; // присваивание
Переменная должна быть инициализирована, прежде чем использоваться (если только это не out-параметр).
Где можно использовать переменную — зависит от области видимости (scope).
Локальные переменные объявляются внутри методов, циклов или блоков и доступны только в пределах блока {…}, в котором они созданы:
void PrintGreeting()
{
string message = "Привет!"; // локальная переменная
Console.WriteLine(message);
} // message уничтожается здесь
if (true)
{
int x = 10;
Console.WriteLine(x); // OK
}
// Console.WriteLine(x); // ОШИБКА: x не существует
В C# нет глобальных переменных, как в C или Python. Но есть статические поля класса, которые по сути ведут себя как «глобальные»:
public class AppState
{
public static string CurrentUser = "admin";
}
Доступ: AppState.CurrentUser. Чрезмерное использование таких полей — антипаттерн (нарушает инкапсуляцию). Обычно можно сделать отдельный статический класс, например, констант, который будет хранить набор чего-то статического для сравнения.
Константы
Константы (Constants) – значения, которые не могут быть изменены во время выполнения программы.
Синтаксис:
const тип Имя = значение;
Константы должны быть инициализированы при объявлении, и являются статическими по умолчанию (принадлежат классу, а не объекту). Значение подставляется на этапе компиляции (не занимает память во время выполнения). Поддерживает только примитивные типы, string, и enum. И константа является статической по умолчанию (принадлежит типу, а не экземпляру).
Отличие от переменной также в том, что константа не требует памяти – значение подставляется компилятором. Это нужно для фиксированных значений.
Шаблон объявления константы:
const <тип> <ИМЯ_КОНСТАНТЫ> = <значение>;
Примеры реализации:
const int MaxAttempts = 3;
const string DefaultCurrency = "RUB";
const double Pi = 3.14159;
var
При работе с переменными, нужно использовать описательные имена, которые дадут понять, что они собой представляют – username, totalPrice, а не x, y.
C# позволяет не указывать тип явно, если он очевиден из правой части выражения.
Если тип очевиден из контекста, можно объявить через var:
var имя = значение;
И это самое распространённое, очень часто можно увидеть именно такой вид - var:
var list = new List<string>(); // тип string понятен
var age = 25; // int
var name = "Alice"; // string
var list = new List<int>(); // List<int>
Если тип неочевиден, лучше предусмотреть и строго типизировать. К примеру:
var result = GetData(); // Что за тип? int? string? object?
Правило: var — не динамический тип. Это синтаксический сахар. Тип определяется на этапе компиляции и не меняется. Помните, что язык C# не динамически типизированный, а строго - это значит, что есть требования к указаниям типов.
Шаблон вывода типа через ключевое слово var:
var <имя> = <значение>;
Примеры реализации:
var count = 10; // int
var name = "Alex"; // string
var users = new List<User>(); // List<User>
var coordinates = (x: 10, y: 20); // ValueTuple
Модификаторы параметров
ref — передача по ссылке (с возможностью изменения). Переменная должна быть инициализирована до передачи. Метод может изменить её значение.
void DoubleValue(ref int x)
{
x *= 2;
}
int number = 5;
DoubleValue(ref number); // number = 10
Полезно, когда нужно изменить исходную переменную.
Шаблон передачи параметра по ссылке с возможностью изменения:
ref <тип> <имяПараметра>
Пример реализации в C#:
void Increment(ref int value)
{
value += 1;
}
int counter = 5;
Increment(ref counter); // counter становится 6
out — выходной параметр. Переменная не обязана быть инициализирована при передаче, но должна быть присвоена внутри метода.
bool TryParse(string input, out int result)
{
if (int.TryParse(input, out result))
return true;
else
{
result = 0;
return false;
}
}
if (TryParse("123", out int value))
{
Console.WriteLine(value); // 123
}
Идеально для методов, возвращающих результат и статус (например, TryParse).
Шаблон выходного параметра:
out <тип> <имяПараметра>
Пример реализации в C#:
bool TryParseInt(string input, out int result)
{
return int.TryParse(input, out result);
}
if (TryParseInt("42", out int number))
{
Console.WriteLine(number); // 42
}
Ключевые слова ref и out используются для передачи аргументов в методы по ссылке, что позволяет изменять значение переменной внутри метода и сохранять эти изменения после завершения метода. ref - когда нужно передать уже существующее значение в метод и позволить методу изменить его, out - когда метод должен вернуть несколько значений (например, для возврата результата и состояния ошибки).
in — передача по ссылке, только для чтения (C# 7.2+). Позволяет передавать большие структуры по ссылке, но запрещает их изменение.
void PrintPerson(in Person person)
{
Console.WriteLine(person.Name);
// person.Name = "xxx"; // ОШИБКА: нельзя изменять
}
var p = new Person { Name = "Bob" };
PrintPerson(in p);
Эффективно для производительности: избегает копирования, но безопасно.
Шаблон передачи параметра по ссылке только для чтения:
in <тип> <имяПараметра>
Пример реализации в C#:
void LogMessage(in string message)
{
Console.WriteLine($"[LOG] {message}");
}
string msg = "System started";
LogMessage(in msg);
params — переменное число аргументов. Позволяет передавать произвольное количество аргументов одного типа.
void PrintNumbers(params int[] numbers)
{
foreach (int n in numbers)
Console.WriteLine(n);
}
PrintNumbers(1, 2, 3, 4); // OK
PrintNumbers(); // OK — пустой массив
Шаблон переменного числа аргументов:
params <тип>[] <имяПараметра>
Пример реализации в C#:
void PrintAll(params string[] messages)
{
foreach (var msg in messages)
Console.WriteLine(msg);
}
PrintAll("A", "B", "C"); // три аргумента
PrintAll(); // ноль аргументов (пустой массив)
Хранение данных в переменной
Что можно хранить в переменной?
- Переменная может содержать:
- Примитивные значения: int, bool, double, char;
- Ссылки на объекты: string,
List<T>, MyClass; - Результат вызова метода
var length = GetName().Length;
var user = CreateUser();
- Анонимные объекты:
var person = new { Name = "Alice", Age = 30 };
- Функции (делегаты):
Func<int, int> square = x => x * x;
Переменные используются также в циклах.
foreach (var item in items)
{
Console.WriteLine(item);
}
Здесь item - локальная переменная, объявленная на каждой итерации. Она копируется из коллекции:
- Для значимых типов (int, struct) — копируется значение.
- Для ссылочных типов (class) — копируется ссылка (объект общий).
Изменение item не повлияет на коллекцию. Для foreach по массиву item — readonly. Чтобы изменить элемент, используйте for.
Шаблон локальной переменной в блоке кода:
{
<тип> <имя> = <значение>;
// <имя> доступно здесь
}
// <имя> недоступно здесь
Пример реализации:
void Process()
{
int outer = 10;
if (true)
{
int inner = 20;
Console.WriteLine(outer + inner); // OK: 30
}
// Console.WriteLine(inner); // Ошибка: переменная не существует
Console.WriteLine(outer); // OK: 10
}
Шаблон переменной в цикле:
for (<тип> <имя> = <начальное>; <условие>; <шаг>)
{
// <имя> доступно здесь
}
// <имя> недоступно здесь
Пример реализации:
for (int i = 0; i < 5; i++)
{
Console.WriteLine(i);
}
// i недоступна после цикла
foreach (var item in collection)
{
Console.WriteLine(item);
}
// item недоступна после цикла
Шаблон поля экземпляра класса:
<модификаторДоступа> <тип> <имяПоля>;
Пример реализации:
public class User
{
private string _username; // приватное поле
public int Age; // публичное поле (не рекомендуется)
protected DateTime CreatedAt; // защищённое поле
}
Шаблон статического поля:
static <тип> <имяПоля>;
Пример реализации:
public class Configuration
{
public static string ApiKey = "secret";
private static int _requestCount = 0;
}
Шаблон доступа к полю текущего объекта:
this.<имяПоля>
Пример реализации в C#:
public class Calculator
{
private int _value;
public void SetValue(int value)
{
this._value = value; // this указывает на поле класса
}
}
Шаблон доступа к статическому полю:
<ИмяКласса>.<имяПоля>
Пример реализации:
int count = Configuration.RequestCount;
Configuration.ApiKey = "new-key";
Шаблон доступа к свойству объекта:
<имяОбъекта>.<имяСвойства>
Пример реализации:
User user = new User();
user.Name = "Alice"; // установка значения
string name = user.Name; // получение значения
Шаблон доступа к элементу коллекции:
<имяКоллекции>[<индекс>]
<имяКоллекции>[<ключ>]
Пример реализации:
int[] numbers = { 1, 2, 3 };
int first = numbers[0]; // 1
Dictionary<string, int> scores = new();
scores["Alice"] = 100;
int aliceScore = scores["Alice"]; // 100
Шаблон анонимного типа:
var <имя> = new { <имяСвойства1> = <значение1>, <имяСвойства2> = <значение2> };
Пример реализации в C#:
var person = new { Name = "Alice", Age = 30 };
Console.WriteLine(person.Name); // Alice
Шаблон кортежа:
var <имя> = (<значение1>, <значение2>, ...);
(<тип1>, <тип2>, ...) <имя> = (<значение1>, <значение2>, ...);
Пример реализации в C#:
var point = (10, 20);
Console.WriteLine(point.Item1); // 10
(int x, int y) coordinates = (30, 40);
Console.WriteLine(coordinates.x); // 30